<?php
namespace Anker1992\BasicLib;

class MysqlPDO
{
    //获取对象句柄
    protected static $_instance = null;
    protected $dbh;
    protected $where = [];
    protected $wheredata = array();
    protected $order = '';

    private function __construct($param)
    {
        try {
            $this->dbh = new \PDO(
                'mysql:host=' . $param['hostname'] . ';port=' . $param['port'] . ';dbname=' . $param['database'],
                $param['username'],
                $param['passport'],
                array(
                    \PDO::ATTR_PERSISTENT => false,
                    \PDO::ATTR_TIMEOUT => 3,
                    \PDO::MYSQL_ATTR_INIT_COMMAND  => "set names 'utf8mb4';"
                )
            );
        } catch (\PDOException $e) {
            throw new \Exception('Mysql Error: ' . $e->getMessage());
            exit;
        }
    }

    private function error($stmt)
    {
        $error = $stmt->errorInfo();
        $this->message = "mysql ERROR:" . $error[1] . " " . $error[2];
        throw new \Exception($this->message);
    }

    private function __clone()
    {
    }

    /**
     * 获取对象实例
     */
    public static function getInstance($param, $instance = 'default')
    {
        if (!isset(self::$_instance[$instance]) || self::$_instance[$instance] == null) {
            self::$_instance[$instance] = new self($param);
        }
        return self::$_instance[$instance];
    }

    /**
     * 查询操作
     * @param string $sql
     * @param string|array $param
     * @return 数组对象
     */
    public function query($sql, $param = '')
    {
        $stmt = $this->dbh->prepare($sql);
        $param = $param != '' && is_array($param) ? array_values($param) : array($param);
        
        if ($stmt->execute($param)) {
            $data = $stmt->fetchAll(\PDO::FETCH_OBJ);
            return $data ? $data : array();
        } else {
            $this->error($stmt);
        }
        return false;
    }

    /**
     * 执行非查询操作
     * @param string $sql
     * @param string|array $param
     * @return bool|int
     */
    public function exec($sql, $param = '')
    {
        $stmt = $this->dbh->prepare($sql);
        $param = $param != '' && is_array($param) ? array_values($param) : array($param);
        if ($stmt->execute($param)) {
            $id = $this->dbh->lastInsertId();
            return $id ? $id : false;
        } else {
            $this->error($stmt);
        }
    }

    /**
     * 插入操作
     * @param string $tablename
     * @param array $data
     * @return bool|int
     */
    public function insert($tablename, $data)
    {
        if (empty($data) || !is_array($data)) {
            return false;
        }
        $setsql = '';
        $vals = '';
        foreach($data as $k => $v) {
            $setsql .= "`{$k}`,";
            $vals .= "?,";
        }
        $setsql = trim($setsql, ",");
        $vals = trim($vals, ",");
        $sql = "INSERT INTO {$tablename}({$setsql}) VALUES ($vals)";

        $stmt = $this->dbh->prepare($sql);
        $data = array_values($data);
        try {
            if ($stmt->execute(array_values($data))) {
                return $this->dbh->lastInsertId();
            } else {
                $this->error($stmt);
            }
        } catch(\Exception $e) {
            throw new \Exception($e->getMessage());
        }
        return false;
    }

    public function clearWhere()
    {
        $this->where = [];
        $this->wheredata = array();
    }

    /**
     * update的where条件
     * @param string $field
     * @param string|int|bool|array $val
     * 例子：
     * $db->where('age>=', 3);
     * $db->where('name', 'anker');
     */
    public function where($field, $val)
    {
        $this->where[] = preg_match('/[=><]/i', $field) ? "{$field}" : "`{$field}`=";
        if (is_array($val)) {
            $this->wheredata = array_merge($this->wheredata, $val);
        } else {
            array_push($this->wheredata, $val);
        }
    }

    /**
     * 更新操作
     * @param string $tablename
     * @param array $data
     * @return bool
     */
    public function update($tablename, $data)
    {
        //防止全局更改
        if (empty($this->where)) {
            return false;
        }
        if (empty($data) || !is_array($data)) {
            return false;
        }
        $setsql = '';
        foreach($data as $k => $v){
            $setsql .= "`{$k}`=?,";
        }
        $setsql = trim($setsql,',');
        //需要更新的数据
        $data = array_values($data);
        $wheresql = implode("? AND ", $this->where). "?";
        $sql = "UPDATE {$tablename} SET {$setsql} WHERE {$wheresql}";
        //将需要更新的数据和条件合并
        $data = array_merge_recursive($data, $this->wheredata);
        $stmt = $this->dbh->prepare($sql);
        return $stmt->execute($data) != false ? true : false;
    }

    /**
     * 获取一行数据
     * @param string $sql
     * @param string|array $param
     * @return 数组对象
     */
    public function getOne($sql, $param = '')
    {
        $data = array();
        $stmt = $this->dbh->prepare($sql);
        $param = $param != '' && is_array($param) ? array_values($param) : array($param);
        if ($param !== '' ? $stmt->execute($param) : $stmt->execute()) {
            $data = $stmt->fetch(\PDO::FETCH_OBJ);
        } else {
            $this->error($stmt);
        }
        return $data ? $data : array();
    }
}
